﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using SocketControl.Protocol.Http.Expand;
using SocketControl.Protocol.Http.Model.General;
using SocketControl.Protocol.Http.General;
using SocketControl.Protocol.Http.Model;

namespace SocketControl.Protocol.Http.RequestMessage
{

    public class Base : GeneralHead, IRequest
    {
        #region first line
        private string method;
        private string resource;
        private string httpversion;
        #endregion
        #region local fileds
        private string accept;
        private string accept_charset;
        private string accept_encoding;
        private string accept_language;
        private string accept_ranges;
        private string authorization;
        private string cookie;
        private string expect;
        private string from;
        private string host;
        private string if_match;
        private string if_modified_since;
        private string if_none_match;
        private string if_range;
        private string if_unmodified_since;
        private string max_forwards;
        private string proxy_authorization;
        private string range;
        private string referer;
        private string te;
        private string user_agent;
        private string warning;
        #endregion

        #region Serialize
        Func<string, RequestMethod> Method = delegate (string param)
        {
            if (!param.IsNull())
            {
                switch (param.ToLower())
                {
                    case "get": { return RequestMethod.GET; }
                    case "connect": { return RequestMethod.CONNECT; }
                    case "delete": { return RequestMethod.DELETE; }
                    case "head": { return RequestMethod.HEAD; }
                    case "options": { return RequestMethod.OPTIONS; }
                    case "post": { return RequestMethod.POST; }
                    case "put": { return RequestMethod.PUT; }
                    case "trace": { return RequestMethod.TRACE; }
                    default: { return RequestMethod.ERROR; }
                }
            }
            else
            {
                return RequestMethod.ERROR;
            }
        };
        Func<string, HttpVersion> HttpVersion = delegate (string param)
        {
            switch (param.ToLower())
            {
                case "http/1.0": { return Model.General.HttpVersion.Http1_0; }
                case "http/1.1": { return Model.General.HttpVersion.Http1_1; }
                default: { return default(Model.General.HttpVersion); }
            }
        };
        Func<string, IList<Model.Item>> Accept = delegate (string param) { return param.Analysis(); };
        Func<string, string> AcceptCharset = delegate (string param) { return param; };
        Func<string, string> AcceptEncoding = delegate (string param) { return param; };
        Func<string, string> AcceptLanguage = delegate (string param) { return param; };
        Func<string, string> AcceptRanges = delegate (string param) { return param; };
        Func<string, string> Authorization = delegate (string param) { return param; };
        Func<string, string> Cookie = delegate (string param) { return param; };
        Func<string, string> Expect = delegate (string param) { return param; };
        Func<string, string> From = delegate (string param) { return param; };
        Func<string, string> Host = delegate (string param) { return param; };
        Func<string, string> IfMatch = delegate (string param) { return param; };
        Func<string, string> IfModifiedSince = delegate (string param) { return param; };
        Func<string, string> IfNoneMatch = delegate (string param) { return param; };
        Func<string, string> IfRange = delegate (string param) { return param; };
        Func<string, string> IfUnmodifiedSince = delegate (string param) { return param; };
        Func<string, string> MaxForwards = delegate (string param) { return param; };
        Func<string, string> ProxyAuthorization = delegate (string param) { return param; };
        Func<string, string> Range = delegate (string param) { return param; };
        Func<string, string> Referer = delegate (string param) { return param; };
        Func<string, string> Resource = delegate (string param) { return param; };
        Func<string, string> TE = delegate (string param) { return param; };
        Func<string, string> UserAgent = delegate (string param) { return param; };
        Func<string, string> Warning = delegate (string param) { return param; };
        private Model.Request Serialize(Model.GeneralHeadModel args)
        {
            return new Model.Request(args)
            {
                Method = Method(this.method),
                Accept = Accept(this.accept),
                Accept_Charset = AcceptCharset(this.accept_charset),
                Accept_Encoding = AcceptEncoding(this.accept_encoding),
                Accept_Language = AcceptLanguage(this.accept_language),
                Accept_Ranges = AcceptRanges(this.accept_ranges),
                Authorization = Authorization(this.authorization),
                Cookie = Cookie(this.cookie),
                Expect = Expect(this.expect),
                From = From(this.from),
                Host = Host(this.host),
                If_Match = IfMatch(this.if_match),
                If_Modified_Since = IfModifiedSince(this.if_modified_since),
                If_None_Match = IfNoneMatch(this.if_none_match),
                If_Range = IfRange(this.if_range),
                If_Unmodified_Since = IfUnmodifiedSince(this.if_unmodified_since),
                Max_Forwards = MaxForwards(this.max_forwards),
                Proxy_Authorization = ProxyAuthorization(this.proxy_authorization),
                Range = Range(this.range),
                Referer = Referer(this.referer),
                Resource = Resource(this.resource),
                TE = TE(this.te),
                User_Agent = UserAgent(this.user_agent),
                Warning = Warning(this.warning)
            };
        }

        #endregion

        #region Deserialize
        Func<Model.Request, string> DeMethod = delegate (Model.Request param)
        {
            switch (param.Method)
            {
                case Model.General.RequestMethod.CONNECT: { return "CONNECT"; }
                case Model.General.RequestMethod.DELETE: { return "DELETE"; }
                case Model.General.RequestMethod.ERROR: { return string.Empty; }
                case Model.General.RequestMethod.GET: { return "GET"; }
                case Model.General.RequestMethod.HEAD: { return "HEAD"; }
                case Model.General.RequestMethod.OPTIONS: { return "OPTIONS"; }
                case Model.General.RequestMethod.POST: { return "POST"; }
                case Model.General.RequestMethod.PUT: { return "PUT"; }
                case Model.General.RequestMethod.TRACE: { return "TRACE"; }
                default: { return string.Empty; }
            }
        };
        Func<Model.Request, string> DeHttpVersion = delegate (Model.Request param)
        {
            switch (param.HttpVersion)
            {
                case Model.General.HttpVersion.Http1_0: { return "HTTP/1.0"; }
                case Model.General.HttpVersion.Http1_1: { return "HTTP/1.1"; }
                default: { return "HTTP/1.1"; }
            }
        };
        Func<Model.Request, string> DeAccept = delegate (Model.Request param) { return param.Accept.DeserializeToMessage(); };
        Func<Model.Request, string> DeAcceptCharset = delegate (Model.Request param) { return param.Accept_Charset; };
        Func<Model.Request, string> DeAcceptEncoding = delegate (Model.Request param) { return param.Accept_Encoding; };
        Func<Model.Request, string> DeAcceptLanguage = delegate (Model.Request param) { return param.Accept_Language; };
        Func<Model.Request, string> DeAcceptRanges = delegate (Model.Request param) { return param.Accept_Ranges; };
        Func<Model.Request, string> DeAuthorization = delegate (Model.Request param) { return param.Authorization; };
        Func<Model.Request, string> DeCookie = delegate (Model.Request param) { return param.Cookie; };
        Func<Model.Request, string> DeExpect = delegate (Model.Request param) { return param.Expect; };
        Func<Model.Request, string> DeFrom = delegate (Model.Request param) { return param.From; };
        Func<Model.Request, string> DeHost = delegate (Model.Request param) { return param.Host; };
        Func<Model.Request, string> DeIfMatch = delegate (Model.Request param) { return param.If_Match; };
        Func<Model.Request, string> DeIfModifiedSince = delegate (Model.Request param) { return param.If_Modified_Since; };
        Func<Model.Request, string> DeIfNoneMatch = delegate (Model.Request param) { return param.If_None_Match; };
        Func<Model.Request, string> DeIfRange = delegate (Model.Request param) { return param.If_Range; };
        Func<Model.Request, string> DeIfUnmodifiedSince = delegate (Model.Request param) { return param.If_Unmodified_Since; };
        Func<Model.Request, string> DeMaxForwards = delegate (Model.Request param) { return param.Max_Forwards; };
        Func<Model.Request, string> DeProxyAuthorization = delegate (Model.Request param) { return param.Proxy_Authorization; };
        Func<Model.Request, string> DeRange = delegate (Model.Request param) { return param.Range; };
        Func<Model.Request, string> DeReferer = delegate (Model.Request param) { return param.Referer; };
        Func<Model.Request, string> DeResource = delegate (Model.Request param) { return param.Resource; };
        Func<Model.Request, string> DeTE = delegate (Model.Request param) { return param.TE; };
        Func<Model.Request, string> DeUserAgent = delegate (Model.Request param) { return param.User_Agent; };
        Func<Model.Request, string> DeWarning = delegate (Model.Request param) { return param.Warning; };
        private void Deserialize(Model.Request param)
        {
            this.httpversion = DeHttpVersion(param);
            this.method = DeMethod(param);
            this.resource = DeResource(param);
            this.accept = DeAccept(param);
            this.accept_charset = DeAcceptCharset(param);
            this.accept_encoding = DeAcceptEncoding(param);
            this.accept_language = DeAcceptLanguage(param);
            this.accept_ranges = DeAcceptRanges(param);
            this.authorization = DeAuthorization(param);
            this.cookie = DeCookie(param);
            this.expect = DeExpect(param);
            this.from = DeFrom(param);
            this.host = DeHost(param);
            this.if_match = DeIfMatch(param);
            this.if_modified_since = DeIfModifiedSince(param);
            this.if_none_match = DeIfNoneMatch(param);
            this.if_range = DeIfRange(param);
            this.if_unmodified_since = DeIfUnmodifiedSince(param);
            this.max_forwards = DeMaxForwards(param);
            this.proxy_authorization = DeProxyAuthorization(param);
            this.range = DeRange(param);
            this.referer = DeReferer(param);
            this.te = DeTE(param);
            this.user_agent = DeUserAgent(param);
            this.warning = DeWarning(param);
        }
        #endregion




        public new string GetMessageString(Model.Request param = null)
        {
            if (param != null)
            {
                this.Deserialize(param);
                base.GetMessageString(param);
            }
            string result = string.Empty;
            #region Get Request Packet 
            #region get http request first line
            if (!this.method.IsNull()) { result.JoinAfterWithSpace(this.method, out result); }
            if (!this.resource.IsNull()) { result.JoinAfterWithSpace(this.resource, out result); }
            result.JoinAfterWithCRLF(this.GetHttpVersion, out result);
            #endregion

            #region get http request fields body
            if (!this.accept.IsNull()) { result.JoinAfterWithCRLF("Accept:" + this.accept, out result); }
            if (!accept_charset.IsNull()) { result.JoinAfterWithCRLF("Accept-Charset:" + this.accept_charset, out result); }
            if (!accept_encoding.IsNull()) { result.JoinAfterWithCRLF("Accept-Encoding:" + this.accept_encoding, out result); }
            if (!accept_language.IsNull()) { result.JoinAfterWithCRLF("Accept-Language:" + this.accept_language, out result); }
            if (!accept_ranges.IsNull()) { result.JoinAfterWithCRLF("Accept-Ranges:" + this.accept_ranges, out result); }
            if (!authorization.IsNull()) { result.JoinAfterWithCRLF("Authorization:" + this.authorization, out result); }
            if (!cookie.IsNull()) { result.JoinAfterWithCRLF("Cookie:" + this.cookie, out result); }
            if (!expect.IsNull()) { result.JoinAfterWithCRLF("Expect:" + this.expect, out result); }
            if (!from.IsNull()) { result.JoinAfterWithCRLF("From:" + this.from, out result); }
            if (!host.IsNull()) { result.JoinAfterWithCRLF("Host:" + this.host, out result); }
            if (!if_match.IsNull()) { result.JoinAfterWithCRLF("If-Match:" + this.if_match, out result); }
            if (!if_modified_since.IsNull()) { result.JoinAfterWithCRLF("If-Modified-Since:" + this.if_modified_since, out result); }
            if (!if_none_match.IsNull()) { result.JoinAfterWithCRLF("If-None-Match:" + this.if_none_match, out result); }
            if (!if_range.IsNull()) { result.JoinAfterWithCRLF("If-Range:" + this.if_range, out result); }
            if (!if_unmodified_since.IsNull()) { result.JoinAfterWithCRLF("If-Unmodified-Since:" + this.if_unmodified_since, out result); }
            if (!max_forwards.IsNull()) { result.JoinAfterWithCRLF("Max-Forwards:" + this.max_forwards, out result); }
            if (!proxy_authorization.IsNull()) { result.JoinAfterWithCRLF("Proxy-Authorization:" + this.proxy_authorization, out result); }
            if (!range.IsNull()) { result.JoinAfterWithCRLF("Range:" + this.range, out result); }
            if (!referer.IsNull()) { result.JoinAfterWithCRLF("Referer:" + this.referer, out result); }
            if (!te.IsNull()) { result.JoinAfterWithCRLF("TE:" + this.te, out result); }
            if (!user_agent.IsNull()) { result.JoinAfterWithCRLF("User-Agent:" + this.user_agent, out result); }
            if (!warning.IsNull()) { result.JoinAfterWithCRLF("Warning:" + this.warning, out result); }
            //Get General Header Message
            result.JoinAfterWithCRLF(base.GetMessageString(), out result);
            #endregion
            #endregion
            return result;
        }
        protected string GetHttpVersion { get { return this.httpversion; } }
        public new Model.Request GetInstance()
        {
            return Serialize(base.GetInstance());
        }


        public new Model.Request GetInstance(string args)
        {
            this.AnalysisMessage(args);
            return Serialize(base.GetInstance(args));
        }

        private void AnalysisMessage(string args)
        {
            int line = 0;
            foreach (string o in args.ReadLine())
            {
                if (line == 0)
                {
                    string[] param = o.Split(' ');
                    if (param.Length == 3)
                    {
                        this.method = param[0];
                        this.resource = param[1];
                        this.httpversion = param[2];
                    }
                }
                else
                {
                    string[] param = AnalysisLine(o);
                    switch (param[0].ToLower())
                    {
                        case "accept": { this.accept = param[1]; break; }
                        case "accept-charset": { this.accept_charset = param[1]; break; }
                        case "accept-encoding": { this.accept_encoding = param[1]; break; }
                        case "accept-ranges": { this.accept_ranges = param[1]; break; }
                        case "authorization": { this.authorization = param[1]; break; }
                        case "cookie": { this.cookie = param[1]; break; }
                        case "expect": { this.expect = param[1]; break; }
                        case "from": { this.from = param[1]; break; }
                        case "host": { this.host = param[1]; break; }
                        case "if-match": { this.if_match = param[1]; break; }
                        case "if-none-match": { this.if_none_match = param[1]; break; }
                        case "if-range": { this.if_range = param[1]; break; }
                        case "if-unmodified-since": { this.if_unmodified_since = param[1]; break; }
                        case "max-forwards": { this.max_forwards = param[1]; break; }
                        case "proxy-authorization": { this.proxy_authorization = param[1]; break; }
                        case "range": { this.range = param[1]; break; }
                        case "referer": { this.referer = param[1]; break; }
                        case "user-agent": { this.user_agent = param[1]; break; }
                        case "warning": { this.warning = param[1]; break; }
                    }
                }
                ++line;
            }
        }
    }

}